<template>
  <div class="file-uploader">
    <uploader
      ref="uploader"
      class="uploader"
      :options="options"
      :autoStart="autoStart"
      @file-added="onFileAdded"
      @file-success="onFileSuccess"
      @file-progress="onFileProgress"
      @file-error="onFileError"
    >
      <uploader-unsupport></uploader-unsupport>
      <uploader-drop>
        <span>附件类型：{{ fileType }}</span>
        <uploader-btn :single="true">
          <i class="el-icon-circle-plus"></i>
          点击上传
        </uploader-btn>
        <span>未选择文件</span>
      </uploader-drop>
      <uploader-list>
        <template slot-scope="props">
          <ul>
            <li v-for="(file, index) in uploadedList" :key="index">
              <div class="uploader-file">
                <p class="img">
                  <img
                    class="el-upload-list__item-thumbnail"
                    :src="
                      fileType === '文档'
                        ? require('../assets/images/file.png')
                        : fileType === '视频'
                        ? require('../assets/images/vedio.png')
                        : fileType === '压缩文件'
                        ? require('../assets/images/zip.png')
                        : require('../assets/images/pic.png')
                    "
                    alt=""
                  />
                </p>
                <div class="preview">
                  <p class="fileNameBox">
                    <span class="fileIcon"></span>
                    {{ file.attach_name }}
                  </p>
                  <div class="filebox">
                    <p class="fileInfoBox">
                      <span class="fileInfoItem">
                        文件大小：{{
                          (file.attach_size / 1024 / 1024).toFixed(2) + "M"
                        }}
                      </span>
                      <span class="fileInfoItem"> {{ fileType }}文件 </span>
                    </p>
                  </div>
                  <div class="preview-btn">
                    <div
                      class="del"
                      @click="handlePropsFileRemove(file, index)"
                    >
                      <img src="../assets/images/del.png" alt="" />
                    </div>
                  </div>
                </div>
              </div>
            </li>
            <li
              v-for="(file, index) in props.fileList"
              :key="file.id"
              class="liItem"
            >
              <uploader-file
                :file="file"
                :list="true"
                ref="uploaderFile"
                :pauseFlag="pauseFlag"
              >
                <template slot-scope="props">
                  <p class="img">
                    <img
                      class="el-upload-list__item-thumbnail"
                      :src="
                        fileType === '文档'
                          ? require('../assets/images/file.png')
                          : fileType === '视频'
                          ? require('../assets/images/vedio.png')
                          : fileType === '压缩文件'
                          ? require('../assets/images/zip.png')
                          : require('../assets/images/pic.png')
                      "
                      alt=""
                    />
                  </p>
                  <div class="preview">
                    <p class="fileNameBox">
                      <span class="fileIcon"></span>
                      {{ file.name }}
                    </p>
                    <div class="filebox">
                      <p class="fileInfoBox">
                        <span class="fileInfoItem">
                          速度：{{ pauseFlag ? 0 : props.formatedAverageSpeed }}
                        </span>
                        <span class="fileInfoItem">
                          已上传：{{
                            (
                              parseFloat(props.formatedSize) * props.progress
                            ).toFixed(1)
                          }}/{{ props.formatedSize }}
                        </span>
                        <span class="fileInfoItem">
                          {{ fileStatusText(props.status) }}
                        </span>
                      </p>
                    </div>
                    <div class="fileProgressBox">
                      <el-progress
                        class="progressLength"
                        :percentage="
                          parseInt(
                            props.progress.toFixed(2) * 100 - 1 < 0
                              ? 0
                              : props.progress.toFixed(2) * 100
                          )
                        "
                      ></el-progress>
                    </div>
                    <div class="preview-btn">
                      <div class="del" @click="handleFileRemove(file, index)">
                        <img src="../assets/images/del.png" alt="" />
                      </div>
                    </div>
                  </div>
                </template>
              </uploader-file>
            </li>
          </ul>
        </template>
      </uploader-list>
    </uploader>
  </div>
</template>
<script type="javasciprt">
/* eslint-disable semi */
/* eslint-disable comma-dangle */
/* eslint-disable space-before-function-paren */
import _ from "lodash";
import axios from "axios";
import SparkMD5 from "spark-md5";

// changeFile 时间抛出 已上传的文件列表(编辑时传入,默认为空)和新上传的文件列表

export default {
  name: "FileUploader",
  props: {
    // 接受的文件类型
    accept: {
      type: String,
      default: "pdf,doc,docx,xls,xlsx",
    },
    // 文件个数，0 则不限制
    count: {
      type: Number,
      default: 0,
    },
    // 文件大小，0 则不限制
    size: {
      type: Number,
      default: 0,
    },
    // 已上传过的文件，用于编辑时用，新建时可不传
    uploadedList: {
      type: Array,
      default: () => [],
    },
    // 显示的文字，【文件、视频】
    fileType: {
      type: String,
      default: "文件",
    },
    // 保存给后端时候的文件类型，【1、2】
    type: {
      type: String,
      default: "1",
    },
    // 文件大小的单位
    unit: {
      type: String,
      default: "M",
    },
  },
  data() {
    var that = this;
    return {
      options: {
        target: "http://sapi.ps.cqooc.com/unit/attach/upload2",
        query: {
          token: sessionStorage.getItem("token"),
        },
        testChunks: true,
        parseTimeRemaining: function (timeRemaining, parsedTimeRemaining) {
          return parsedTimeRemaining
            .replace(/\syears?/, "年")
            .replace(/\days?/, "天")
            .replace(/\shours?/, "小时")
            .replace(/\sminutes?/, "分钟")
            .replace(/\sseconds?/, "秒");
        },
        checkChunkUploadedByResponse: function (chunk, message) {
          // const obj = JSON.parse(message);
          // if (obj.isexist) {
            // that.statusTextMap.success = "秒传文件";
            // return true;
          // }
        },
      },
      pauseFlag: "",
      autoStart: false,
      statusTextMap: {
        success: "上传成功",
        error: "上传出错了",
        uploading: "上传中...",
        paused: "计算md5...",
        waiting: "等待中...",
        cmd5: "计算md5...",
      },
      uploadedStatus: false,
      fileList: [],
      arrList:[],
      token: sessionStorage.getItem("token"),
      fileStatusText: (status, response) => {
        return this.statusTextMap[status];
      },
    };
  },
  methods: {
    // 添加文件
    onFileAdded(file) {
      const length = this.uploadedList.length + this.fileList.length;
      this.uploadedStatus = true;
      this.$emit("uploadedStatus", this.uploadedStatus);
      // 附件个数大于等于限制的个数，并且限制个数不为 0
      if (length >= this.count && this.count !== 0) {
        this.$message.error(`只允许上传${this.count}个文件`);
        file.ignored = true;
        file.cancel();
        this.uploadedStatus = false;
        this.$emit("uploadedStatus", this.uploadedStatus);
        return false;
      } else {
        // 开始上传
        const fileExtension = file.getExtension();
        // 判断文件格式
        const isInAccept = this.checkExtensions(fileExtension);
        // 判断文件大小是否可以
        const isInSize = this.checkSize(file.size);
        // 文件格式或者大小不符合，取消上传
        if (!isInAccept || !isInSize) {
          file.ignored = true;
          file.cancel();
          this.uploadedStatus = false;
          this.$emit("uploadedStatus", this.uploadedStatus);
          return false;
        } else {
          this.panelShow = true;
          this.show_filename = false;
          this.computeMD5(file);
        }
      }
    },
    // 文件上传成功
    onFileSuccess(rootFile, file, response, chunk) {
      const { name, size, uniqueIdentifier,chunks } = file;
      const { url, merge } = JSON.parse(response);
      const newFile = {};
      newFile.attach_name = name;
      newFile.attach_url = url;
      newFile.attach_size = size;
      newFile.type = this.type;
      this.fileList.push(newFile);
      this.emitData(this.uploadedList, this.fileList);
      const datatmp = new FormData();
      datatmp.append("token", this.token);
      datatmp.append("filename", name);
      datatmp.append("identifier", uniqueIdentifier);
      datatmp.append("totalSize", size);
      datatmp.append("totalChunks", chunks.length);
      this.uploadedStatus = false;
      this.$emit("uploadedStatus", this.uploadedStatus);
      if(url === undefined){
        if (merge) {
        axios
          .post(
            "http://sapi.ps.cqooc.com/unit/attach/upload2?action=merge",
            datatmp
          )
          .then((res) => {
            if (res.data.code === 0) {
              // if(res.data.url != undefined || res.data.url != '' || 'url' in res.data){
                newFile.attach_url = res.data.url;
                this.emitData(this.uploadedList, this.fileList);
                this.uploadedStatus = false;
                this.$emit("uploadedStatus", this.uploadedStatus);
                console.warn("onFileSuccess", "上传成功");
              // }
            } else {
              that.fileStatusText(error);
              this.uploadedStatus = true;
              this.$emit("uploadedStatus", this.uploadedStatus);
            }
          })
          .catch(function (error) {
            this.$message.error('上传失败，请重新上传！')
          });
        }
      }
    },
    // 检查后缀名
    checkExtensions(extension) {
      const accept = _.map(this.accept.split(","), (item) => _.trim(item));
      if (!_.includes(accept, extension)) {
        this.$message.warning(`请上传${accept.join(",")}的格式!`);
        return false;
      }
      return true;
    },
    // 检查大小
    checkSize(fileSize) {
      var smallThanLimitSize = fileSize / 1024 / 1024 < this.size;
      if (!smallThanLimitSize) {
        this.$message.warning(`文件大小不能大于${this.size}${this.unit}!`);
        return false;
      }
      return true;
    },
    // 计算 md5
    computeMD5(file) {
      const blobSlice =
        File.prototype.slice ||
        File.prototype.mozSlice ||
        File.prototype.webkitSlice;
      var chunkSize = 1048576;
      var chunks = Math.ceil(file.size / chunkSize);
      var currentChunk = 0;
      var spark = new SparkMD5.ArrayBuffer();
      var fileReader = new FileReader();
      var time = new Date().getTime();
      file.cmd5 = true;
      fileReader.onload = (e) => {
        spark.append(e.target.result);
        currentChunk++;
        if (currentChunk < chunks) {
          console.log(
            `第${currentChunk}分片解析完成, 开始第${
              currentChunk + 1
            } / ${chunks}分片解析`
          );
          loadNext();
        } else {
          console.log("finished loading");
          const md5 = spark.end();
          console.log(
            `MD5计算完成：${file.name} \nMD5：${md5} \n分片：${chunks} 大小:${
              file.size
            } 用时：${new Date().getTime() - time} ms`
          );
          spark.destroy();
          file.uniqueIdentifier = md5;
          file.cmd5 = false;
          file.resume();
        }
      };
      fileReader.onerror = () => {
        console.warn("oops, something went wrong.");
        file.cancel();
      };
      const loadNext = () => {
        var start = currentChunk * chunkSize;
        var end =
          start + chunkSize >= file.size ? file.size : start + chunkSize;
        fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
      };
      loadNext();
    },
    onFileError(rootFile, file, response, chunk) {
      this.$message.error("文件上传失败，请重新上传");
      this.uploadedStatus = true;
      this.$emit("uploadedStatus", this.uploadedStatus);
    },
    onFileProgress(rootFile, file, chunk) {
      this.uploadedStatus = true;
      this.$emit("uploadedStatus", this.uploadedStatus);
    },
    // 删除 props 中的文件
    handlePropsFileRemove(file) {
      const newList = _.filter(
        this.uploadedList,
        (item) => item?.attach_id !== file?.attach_id
      );
      this.uploadedStatus = false;
      this.$emit("uploadedStatus", this.uploadedStatus);
      this.emitData(newList, this.fileList);
    },
    // 删除新上传的文件
    handleFileRemove(file, index) {
      this.uploadedStatus = false;
      this.$emit("uploadedStatus", this.uploadedStatus);
      const newList = [];
      this.fileList.forEach((item, idx) => {
        if (idx !== index) {
          newList.push(item);
        }
      });
      this.fileList = newList;
      file.cancel();
      this.emitData(this.uploadedList, newList);
    },
    emitData(uploaded, fileList) {
      // 将新上传与已上传的文件传给父组件
      this.$emit("changeFile", uploaded, fileList);
    },
  },
};
</script>
<style lang='scss' scoped>
img {
  width: 100%;
  height: 100%;
}
.uploader-drop {
  border: none;
  background-color: transparent;
  padding: 0;
  & > span:first-of-type {
    margin-right: 10px;
  }
  span {
    font-size: 16px;
  }
}
.uploader .uploader-btn {
  margin-right: 4px;
}
.uploader .uploader-list {
  max-height: 440px;
  width: 60%;
  overflow: auto;
  overflow-x: hidden;
  overflow-y: auto;
}
.uploader-file {
  position: relative;
  display: flex;
  align-items: center;
  height: auto;
  margin-top: 10px;
  border: none;
  width: 100%;
  padding: 10px 22px;
  background-color: #f4f7fc;
  border-radius: 5px;
}
.uploader-btn {
  padding: 5px 10px 5px 10px;
  margin-right: 10px;
  background-color: #e5eefe;
  border: solid 1px #c8e3fe;
  color: #2197fd;
  border-radius: 5px;
  font-size: 14px;
  letter-spacing: 1px;
  &:hover {
    background-color: #e5eefe;
    border: solid 1px #c8e3fe;
  }
}
.el-progress {
  width: 95%;
  display: flex;
  align-items: center;
}
.img {
  font-size: 0;
  width: 30px;
  height: 30px;
  margin-right: 30px;
  img {
    display: block;
  }
}
.preview {
  width: 85%;
}
.fileProgressBox {
  display: flex;
  align-items: center;
}
.filebox {
  display: flex;
}
.fileNameBox {
  display: flex;
  width: 100%;
  line-height: 20px;
  font-size: 16px;
}
.fileInfoBox {
  width: 100%;
  line-height: 20px;
  display: flex;
  flex-wrap: wrap;
}
.fileInfoItem {
  margin-right: 20px;
  line-height: 28px;
  font-size: 16px;
}
.preview-btn {
  position: absolute;
  right: 3%;
  top: 50%;
  height: 25px;
  transform: translateY(-50%);
  width: 3%;
  font-size: 0;
  .del {
    width: 80%;
    height: 80%;
    float: left;
    img {
      display: block;
    }
  }
}
/deep/.el-dialog__body {
  padding: 10px 20px 20px !important;
}
.main {
  position: relative;
  .page-number {
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    color: #000;
    z-index: 1;
  }
  .el-icon-arrow-left,
  .el-icon-arrow-right {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    font-size: 30px;
    color: #000;
    z-index: 1;
  }
  .el-icon-arrow-left {
    left: 10px;
  }
  .el-icon-arrow-right {
    right: 10px;
  }
}
/deep/.filePreview {
  height: 100%;
  i {
    font-size: 20px;
  }
  /deep/.el-dialog__header {
    padding: 0.25rem 0.25rem 0.125rem;
  }
  /deep/.el-dialog__body {
    padding-top: 0 !important;
    height: 90%;
  }
  /deep/.el-icon-rank {
    position: absolute;
    right: 3%;
    top: 0.28rem;
    font-size: 16px !important;
    color: #909399;
  }
}
</style>
